package com.boot2.core.web;

import com.boot2.core.constant.HttpConstant;
import com.boot2.core.utils.CheckUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.SneakyThrows;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.util.CollectionUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.servlet.HandlerMapping;

import javax.servlet.http.HttpServletRequest;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.Map;

/**
 * @author zhangweilin
 * @Description: 拓展RestTemplate, 如果方法名不带"Form"字样，除了get形式，传参都是以json方式，被调用方均以@RequestBody形式接收，当方法名是有"Form"字样时，表示按表单形式请求
 * @date 2020/5/11
 */
abstract public class AbstractRestTemplate extends RestTemplate {

    public static final String paramMapKey = "_restTemplate_paramMap";
    public static final String refreshTokenParamMapKey = "_restTemplate_refreshToken_paramMap";
    public static final String refreshTokenMapKey = "refreshToken";


    /**
     * 发送/获取 服务端数据(主要用于解决发送put,delete方法无返回值问题).
     *
     * @param url      绝对地址
     * @param method   请求方式
     * @param bodyType 返回类型
     * @param <T>      返回类型
     * @return 返回结果(响应体)
     */
    @SneakyThrows
    protected <T> T jsonExchange(String url, HttpMethod method, Object paramObj, Class<T> bodyType) {
        HttpEntity<String> entity = getJsonHttpEntity(paramObj);
        ResponseEntity<T> resultEntity = super.exchange(url, method, entity, bodyType);
        return resultEntity.getBody();
    }

    /**
     * 发送/获取 服务端数据(主要用于解决发送put,delete方法无返回值问题).
     *
     * @param url      绝对地址
     * @param method   请求方式
     * @param bodyType 返回类型
     * @param <T>      返回类型
     * @return 返回结果(响应体)
     */
    @SneakyThrows
    protected <T> T jsonExchange(URI url, HttpMethod method, Object paramObj, Class<T> bodyType) {
        HttpEntity<String> entity = getJsonHttpEntity(paramObj);
        ResponseEntity<T> resultEntity = super.exchange(url, method, entity, bodyType);
        return resultEntity.getBody();
    }


    /**
     * 发送/获取 服务端数据(主要用于解决发送put,delete方法无返回值问题).
     *
     * @param url          绝对地址
     * @param method       请求方式
     * @param bodyType     返回类型
     * @param <T>          返回类型
     * @param uriVariables
     * @return 返回结果(响应体)
     */
    @SneakyThrows
    protected <T> T jsonExchange(String url, HttpMethod method, Object paramObj, Class<T> bodyType, Object... uriVariables) {
        HttpEntity<String> entity = getJsonHttpEntity(paramObj);
        ResponseEntity<T> resultEntity = super.exchange(url, method, entity, bodyType, uriVariables);
        return resultEntity.getBody();
    }

    /**
     * 发送/获取 服务端数据(主要用于解决发送put,delete方法无返回值问题).
     *
     * @param url          绝对地址
     * @param method       请求方式
     * @param bodyType     返回类型
     * @param <T>          返回类型
     * @param uriVariables
     * @return 返回结果(响应体)
     */
    @SneakyThrows
    protected <T> T jsonExchange(String url, HttpMethod method, Object paramObj, Class<T> bodyType, Map<String, ?> uriVariables) {
        HttpServletRequest request1 = RequestContext.getRequest();
        Map<String, Object> map = (Map<String, Object>) request1.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
        if (!CollectionUtils.isEmpty(uriVariables)) {
            map.putAll(uriVariables);
        }
        HttpEntity<String> entity = getJsonHttpEntity(paramObj);
        ResponseEntity<T> resultEntity = super.exchange(url, method, entity, bodyType, map);

        return resultEntity.getBody();
    }


    protected HttpEntity<String> getFormHttpEntity(HttpHeaders headers) {
        MimeType mimeType = MimeTypeUtils.parseMimeType(HttpConstant.contentTypeFormUTF8);
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);
        return new HttpEntity<>(null, headers);
    }

    protected HttpEntity<MultiValueMap<String, String>> getFormHttpEntity(Object paramObj) {
        HttpHeaders headers = new HttpHeaders();
        MimeType mimeType = MimeTypeUtils.parseMimeType(HttpConstant.contentTypeFormUTF8);
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);

        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
        if (paramObj instanceof Map) {
            Map map = (Map) paramObj;
            map.forEach((k, v) -> {
                //只能用add,因为value是一个list,继承结构为 Map<K, List<V>>，用put会因不能转换为List而抛异常
                paramsMap.add(k.toString(), v.toString());
            });
        }

        HttpEntity<MultiValueMap<String, String>> httpEntity = new HttpEntity<>(paramsMap, headers);
        return httpEntity;
    }

    protected HttpEntity<MultiValueMap<String, String>> getFormHttpEntity(Object paramObj, HttpHeaders headers) {
        MimeType mimeType = MimeTypeUtils.parseMimeType(HttpConstant.contentTypeFormUTF8);
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);

        MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
        if (paramObj instanceof Map) {
            Map map = (Map) paramObj;
            map.forEach((k, v) -> {
                //只能用add,因为value是一个list,继承结构为 Map<K, List<V>>，用put会因不能转换为List而抛异常
                paramsMap.add(k.toString(), v.toString());
            });
        }
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(paramsMap, headers);
        return requestEntity;
//        return new HttpEntity<>(paramObj, headers);
    }

    protected HttpEntity<String> getJsonHttpEntity(Object paramObj) throws JsonProcessingException {
        // 请求头
        HttpHeaders headers = new HttpHeaders();
//        MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");
        MimeType mimeType = MimeTypeUtils.parseMimeType(HttpConstant.contentTypeJsonUTF8);
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);
        //提供json转化功能
        ObjectMapper mapper = new ObjectMapper();
        String str = null;
        if (null != paramObj) {
            str = mapper.writeValueAsString(paramObj);
        }
//        System.out.println("exchange,str = " + str);
        // 发送请求
        return new HttpEntity<>(str, headers);
    }

    protected HttpEntity<String> getJsonHttpEntity(Object paramObj, HttpHeaders headers) throws JsonProcessingException {
        // 请求头
//        HttpHeaders headers = new HttpHeaders();
//        MimeType mimeType = MimeTypeUtils.parseMimeType("application/json");
        MimeType mimeType = MimeTypeUtils.parseMimeType(HttpConstant.contentTypeJsonUTF8);
        MediaType mediaType = new MediaType(mimeType.getType(), mimeType.getSubtype(), Charset.forName("UTF-8"));
        // 请求体
        headers.setContentType(mediaType);
        //提供json转化功能
        ObjectMapper mapper = new ObjectMapper();
        String str = null;
        if (null != paramObj) {
            str = mapper.writeValueAsString(paramObj);
        }
//        System.out.println("exchange,str = " + str);
        // 发送请求
        return new HttpEntity<>(str, headers);
    }

    protected HttpHeaders getHttpHeaders(Map<String, String> headerMap) {
        HttpHeaders headers = new HttpHeaders();
        if (CheckUtil.isNotEmpty(headerMap)) {
            headerMap.forEach((k, v) -> {
                headers.add(k, v);
            });
        }
        return headers;
    }

}

//restTemplate发送POST请求时可以通过restTemplate.postForObject(url.toString(),httpEntity,String.class)
//        方式请求，但是GET却没有相应的方法，但是可以使用exchange替代，代码如下：
//        HttpHeaders headers = new HttpHeaders();
//        headers.add("token",token);
//        HttpEntity<String> httpEntity = new HttpEntity<>(null, headers);
//        ResponseEntity<String> resEntity = restTemplate.exchange(url.toString(), HttpMethod.GET, httpEntity, String.class);

//    MultiValueMap<String, Object> postParameters = new LinkedMultiValueMap<>();
//postParameters.add("mobile", phone);
//        postParameters.add("smsCaptcha", code);
//        postParameters.add("action", "unKnown");
//        HttpHeaders headers = new HttpHeaders();
//        headers.add("Content-Type", "application/x-www-form-urlencoded");
//        HttpEntity<MultiValueMap<String, Object>> r = new HttpEntity<>(postParameters, headers);
//        ResponseMessage responseMessage = restTemplate.postForObject(url, r, ResponseMessage.class);
